# encoding  :  utf-8 _*_
# @author   :  朱清闯
# @software :  PyCharm
# time      :  2022/3/19 13:09
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_extensions.cache.mixins import CacheResponseMixin
from rest_framework.decorators import action
from account.serializers import UserSimpleModelSerializer, UserApplicationModelSerializer, UserVIPApplicationModelSerializer
from account.serializers import UserNicknameApplicationModelSerializer, UserSerializer, NotificationModelSerializer
from account.serializers import CustomerBankPointChangeLogModelSerializer, WithdrawLogModelSerializer, RechargeLogModelSerializer
from account.serializers import SponsorModelSerializer
from account.models import UserActivateApplication, User, CustomerBankPointChangeLog, Company,UserVIPApplication, UserNicknameApplication
from account.models import Notification, WithdrawLog, RechargeLog, Sponsor
from account.models import ClassGrade, UserOfClass
from account.serializers import UserOfClassModelSerializer, ClassGradeModelSerializer, ClassGradeSimpleModelSerializer
from utils import captchaimage, Huyiwuxian, SaveImage
from utils import VerifyPhoneAndUsernameHasRegistered
from utils.GenarateRandCode import generate_random_code
from utils.response_result import error_result
from utils.GenerateToken import create_token
from utils.auth import Authentication
from utils.Mypermission import IsOwnerPermission, IsAdmin
import datetime
import re
from django.db.models import Q, F
from django.core.cache import cache
from utils.myViewSet import CustomNoQuestionsModelViewSet
from utils.MyPage import SmallPage
from datetime import date, timedelta
import time
import random
from django.contrib.auth.hashers import check_password, make_password
from django.db import transaction
from celery_tasks.bankpoint.tasks import create_customer_bank_point_log_change
import csv

msg_captcha_success = '获取captcha成功！'
data_error_text = "数据格式不正确"
data_add_text = '恭喜，添加成功'
data_query_fail = "查询没有记录"
data_parameters_error = "查询参数错误"
invite_award_points = 20
register_award_points = 200


def convert_dic_list(dict_list, key='id'):
    # 使用列表推导式提取每个字典中'id'的值
    return [d[key] for d in dict_list]


# 第1次请求
class SendCaptcha(APIView):
    """
    返回4位验证码图片,是base64编码的图片字节流
    """
    permission_classes = []
    authentication_classes = []

    def get(self, request):
        try:
            captcha_code, data = captchaimage.generate_captcha_image(code_type=1, code_len=4)
            # 第一次请求验证码
            cache.set(captcha_code, True, 10 * 60)
            response = error_result(code=200, results=data, msg=msg_captcha_success)
            return Response(response)
        except Exception as e:
            response = error_result(500)
            print(e)
        return Response(response)


# 第2次请求，验证captcha,并附加rand2,更新rand1的value为rand2
class VerifyCaptchaCodeView(APIView):
    """
    验证captcha,并附加rand2,更新rand1的value为rand2
    """
    authentication_classes = []
    permission_classes = []

    def get(self, request):
        try:
            username = request.GET.get('username')
            phone = request.GET.get('phone')
            result_code = VerifyPhoneAndUsernameHasRegistered.verify(phone=phone, username=username)
            if result_code > 0:
                response = error_result(code=result_code)
                return Response(response)
            rand1 = request.GET.get('rand1')
            rand1_session = cache.get(rand1)
            if rand1_session:
                # 以rand1为key，rand2为value,作为第二次来请求短信验证码的依据
                rand2 = generate_random_code(type_code=1, length=4)
                data = {"rand2": rand2}
                cache.set(rand1, rand2, 10 * 60)
                response = error_result(code=200, results=data)
            else:
                response = error_result(400)
        except Exception as e:
            response = error_result(0)
            print(e)
        return Response(response)


# 发送手机短信验证码
# 第3次发送接收前端的rand1和rand2，如果验证通过，发送手机短信，要求该手机号码未被注册
class SendCodeView(CacheResponseMixin, APIView):
    """
    发送接收前端的rand1和rand2，如果验证通过，发送手机短信,返回是否发送成功
    """
    permission_classes = []
    authentication_classes = []

    def get(self, request):
        phone_number = request.query_params.get('phoneNumber')
        client_code = request.query_params.get('clientCode')
        captcha_code = request.GET.get('captchaCode')
        captcha_code = captcha_code.upper()
        server_client_code = cache.get(captcha_code)
        if server_client_code != client_code:
            return Response(error_result(code=1015))
        if not phone_number:
            return Response(error_result(code=1005, msg='手机号码不能空'))
        mobile_pat = re.compile(r'^1[3-9]\d{9}$')
        res = re.search(mobile_pat, phone_number)
        if not res:
            return Response(error_result(code=1004, msg="手机号码不合法"))
        # 检测是否发送过验证码，如果没有发送过则发送，否则另作分类讨论处理
        server_phone_code = cache.get(phone_number)
        # 如果这个手机号已经发送过
        if server_phone_code:
            last_send_time = cache.get('last_time' + phone_number)
            # print("last_send_time", last_send_time)
            if last_send_time and last_send_time > (datetime.datetime.now() - datetime.timedelta(minutes=1)):
                # 距离上次发送验证码不足1分钟！
                return Response(error_result(code=1018))
        # 生成随机数验证码,设定验证码的过期时间为5分钟以后,发送验证码，存入缓存
        phone_code = generate_random_code(type_code=2, length=5)
        cache.set(captcha_code, phone_number, 5 * 60)
        cache.set(phone_number, phone_code, 5 * 60)
        cache.set('last_time' + phone_number, datetime.datetime.now(), 5 * 60)  # 用于检测是否在1分钟中内连续发送验证码

        # 调用发送模块
        mss_status = Huyiwuxian.send_message_by_huyiwuxian(mobile=phone_number, message_code=phone_code)
        response = error_result(code=200, results=mss_status)
        return Response(response)


class WXSendCodeView(CacheResponseMixin, APIView):
    """
    微信端发送手机验证码，没有图形验证码，client_code是手机短信验证码，检测该手机号码是否合法、一分钟内有没有重复发
    """
    permission_classes = []
    authentication_classes = []

    def get(self, request):
        phone_number = request.query_params.get('phoneNumber')
        if not phone_number:
            return Response(error_result(code=1005, msg='手机号码不能空'))
        mobile_pat = re.compile(r'^1[3-9]\d{9}$')
        res = re.search(mobile_pat, phone_number)
        if not res:
            return Response(error_result(code=1004, msg="手机号码不合法"))
        # 检测是否发送过验证码，如果没有发送过则发送，否则另作分类讨论处理
        server_phone_code = cache.get(phone_number)
        # 如果这个手机号已经发送过
        if server_phone_code:
            last_send_time = cache.get('last_time' + phone_number)
            # print("last_send_time", last_send_time)
            if last_send_time and last_send_time > (datetime.datetime.now() - datetime.timedelta(minutes=1)):
                # 距离上次发送验证码不足1分钟！
                return Response(error_result(code=1018))
        # 生成随机数验证码,设定验证码的过期时间为5分钟以后,发送验证码，存入缓存
        phone_code = generate_random_code(type_code=2, length=5)
        cache.set(phone_number, phone_code, 5 * 60)
        cache.set('last_time' + phone_number, datetime.datetime.now(), 5 * 60)  # 用于检测是否在1分钟中内连续发送验证码
        # 调用发送模块
        mss_status = Huyiwuxian.send_message_by_huyiwuxian(mobile=phone_number, message_code=phone_code)
        return Response(error_result(code=200, results=mss_status))


# 根据用户名或者手机号码，产生token,并存入缓存redis
def user_token(username, user):
    token = create_token(username=username)
    cache.set(token, user, 7 * 24 * 60 * 60)
    cache.set(user.username, token, 7 * 24 * 60 * 60)
    cache.set(user.phone, token, 7 * 24 * 60 * 60)
    token = cache.get(username)
    return token


# 微信端和pc端共用同一个接口，注册成功后，发送token，客户端保存好token
# 第4次发送接收rand1 rand2和验证码，检测合格后，手机号码和用户名唯一，发送接收rand1 rand2和验证码，检测合格后，返回是否注册成
class RegisterView(APIView):
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        try:
            # phone_number是表单中的手机号码字段，inviter是邀请者字段，phone_code是短信验证码字段，real_name是姓名字段
            phone_number = request.data.get('phoneNumber')
            inviter = request.data.get('inviter')
            phone_code = request.data.get('phoneCode')
            real_name = request.data.get('real_name')
            server_phone_code = cache.get(phone_number)
            phone_server = User.objects.filter(phone=phone_number).last()
            client_type = request.data.get('clientType')
            # error_result是定制Response的参数，code是返回的状态码，msg是返回的提示信息，results是返回的实际数据
            if not real_name:
                return Response(error_result(code=1016))
            elif not phone_number:
                return Response(error_result(code=1005))
            elif not phone_code:
                return Response(error_result(code=1010))
            elif not server_phone_code:
                return Response(error_result(code=1019))
            elif server_phone_code != phone_code:
                return Response(error_result(code=1017))
            elif phone_server:
                return Response(error_result(code=1006))
            elif server_phone_code == phone_code:
                # is_active表示该用户未激活
                user = User(username=real_name, phone=phone_number, password=make_password("123456"), real_name=real_name,
                            nickname=real_name, is_active=False)
                user.save()
                data = UserSimpleModelSerializer(user).data
                # UserApplicationModelSerializer是用户申请的数据表模型，供管理员审核使用
                activate_application_dic = {'user': user.id, 'status': 0}
                activate_serializer = UserApplicationModelSerializer(data=activate_application_dic)
                if not activate_serializer.is_valid():
                    return Response(error_result(code=201, msg="注册成功，请联系管理员激活账号", results=activate_serializer.errors))
                else:
                    activate_serializer.save()
                # 如果表单中有邀请者，则为该邀请者已经邀请新用户注册的数量增加1，该邀请者每邀请他人注册成功，则奖励bank_point数量5个
                if inviter:
                    inviter_user = User.objects.filter(Q(phone=inviter) | Q(username=inviter))
                    if inviter_user:
                        inviter_user = inviter_user.first()
                        # inviter_user.inviter_number = F('inviter_number') + 1
                        # company_user = Company.objects.first()
                        # CustomerBankPointChangeLog是bankPoint金币交易记录，公司用户给该邀请者奖励bankpoint金币
                        # CustomerBankPointChangeLog.objects.create(receiver=inviter_user, operator=company_user,
                        #                                           point_amount=20)
                        # inviter_user.save()
                        # 获取公司账号, 奖励给邀请者积分20个
                        username_company = Company.objects.first().president
                        user_company = User.objects.get(username=username_company)
                        create_customer_bank_point_log_change.delay(receiver=inviter_user.pk,
                                                                    operator=user_company.pk,
                                                                    point_amount=invite_award_points,
                                                                    remarks='邀请他人注册新账号')
                token = user_token(username=user.username, user=user)
                # 如果是微信端，把token也写入用户资料中
                if client_type == 'wx_client':
                    data = UserSimpleModelSerializer(user).data
                    data['token'] = token
                    response = error_result(code=200, msg='注册成功，密码:123456，请联系管理员激活账号', results=data)
                else:
                    data = {'token': token, 'user': UserSimpleModelSerializer(user).data}
                    response = error_result(code=200, msg='注册成功，密码:123456，请联系管理员激活账号', results=data)
                return Response(response)
        except Exception as e:
            print(e)
            return Response(error_result(code=500))


# 手机号码和用户名都可以登录，登录成功后把{token:user}存入缓存
class LoginView(APIView):
    """
    post:
    手机号码和用户名都可以登录，登录成功后把{token:user}存入缓存,若登录成功，返回ｔｏｋｅｎ
    """
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        try:
            rand_code = request.data['rand_code']
            username = request.data['username']
            password = request.data['password']
            rand_code = rand_code.upper()
            if not password:
                return Response(error_result(code=1002))
            if not username:
                return Response(error_result(code=1001))
            if not rand_code:
                return Response(error_result(code=1010))
            # 先验证是否为机器人，输入正确的验证码
            cache_code = cache.get(rand_code)
            if not cache_code:
                return Response(error_result(code=1011))
            # 用户名和手机号码均可登录
            user = User.objects.filter(Q(username=username) | Q(phone=username)).first()
            if not user:
                response = error_result(code=1003, results='no', msg='用户名错误')
                return Response(response)
            password_match = check_password(password, user.password)
            if not password_match:
                return Response(error_result(code=1003, results='no', msg='密码错误'))
            if not user.is_active:
                return Response(error_result(code=1023, results='no', msg='用户未激活'))
            token = user_token(username=username, user=user)
            # print(token)
            data = {'token': token, 'user': UserSimpleModelSerializer(user).data}
            response = error_result(code=200, results=data, msg='登录成功！')
        except Exception as e:
            print(e)
            response = error_result(code=500)
        return Response(response)

    def get(self, request, format=None):
        code, data = captchaimage.generate_captcha_image(code_type=3, code_len=4)
        # 第一次请求验证码
        cache.set(code, True, 5 * 60)
        response = error_result(code=200, results=data, msg=msg_captcha_success)
        return Response(response)


# 微信端登录专用，没有图形验证码，只有手机号码和密码
class WXLoginView(APIView):
    """
    post:
    手机号码和用户名都可以登录，登录成功后把{token:user}存入缓存,若登录成功，返回token
    """
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        try:
            username = request.data['username']
            password = request.data['password']
            if not password:
                return Response(error_result(code=1002))
            if not username:
                return Response(error_result(code=1001))
            # 用户名和手机号码均可登录
            user = User.objects.filter(Q(username=username) | Q(phone=username)).first()
            if not user:
                response = error_result(code=1003, results={}, msg='用户名错误')
                return Response(response)
            password_match = check_password(password, user.password)
            if not password_match:
                return Response(error_result(code=1003, results={}, msg='密码错误'))
            if not user.is_active:
                return Response(error_result(code=1023, results={}, msg='用户未激活'))
            token = user_token(username=username, user=user)
            # print(token)
            # 把token扁平化到用户资料中
            data = UserSimpleModelSerializer(user).data
            data['token'] = token
            return Response(error_result(code=200, results=data, msg='登录成功！'))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))


class CaptchaPicture(APIView):
    """
    不需要参数，返回验证码图片的base64字符串
    """
    authentication_classes = []
    permission_classes = []

    def get(self, request, format=None):
        code, picture_url = captchaimage.generate_captcha_image(code_type=3, code_len=4)
        # 第一次请求验证码
        cache.set(code, True, 5 * 60)
        response = error_result(code=200, results=picture_url, msg=msg_captcha_success)
        return Response(response)


# 接受客户端的随机码，产生图形验证码
class CaptchaPictureWithClientCode(APIView):
    """
    get:
    发需要参数，返回验证码图片的url字符串
    """
    authentication_classes = []
    permission_classes = []

    def get(self, request, format=None):
        try:
            client_code = request.query_params.get('clientCode')
            # print("收到clientCode:", client_code)
            if client_code:
                code, base64_data = captchaimage.generate_captcha_image(code_type=3, code_len=4)
                print("验证码：", code)
                cache.set(code, client_code, 8 * 60)
                data = base64_data
                # print("缓存后的base64:", base64_data)
                response = Response(error_result(code=200, results=data, msg=msg_captcha_success))
            else:
                response = Response(error_result(code=1020, results='获取失败', msg='前端缺乏随机号码！'))
            return response
        except Exception as E:
            print(E)
            return Response(error_result(code=500, results='no'))


# 检测图形验证码是否正确
class CheckCaptchaCode(APIView):
    """
    get:
    发需要参数，返回验证结果
    """
    authentication_classes = []
    permission_classes = []

    def get(self, request):
        client_code = request.query_params.get('clientCode')
        captcha_code = request.query_params.get('captchaCode')
        captcha_code = captcha_code.upper()
        code_server = cache.get(captcha_code)
        if code_server:
            if client_code == code_server:
                response = error_result(code=200, results=True, msg='ok')
            else:
                response = error_result(code=1069, results=False, msg='no')
        else:
            response = error_result(code=1069, results=False, msg='no')
        return Response(response)


# 未注册返回true,已经注册返回false
class CheckPhoneUsable(APIView):
    """
    get:
    不需要参数，返回验证结果
    """
    authentication_classes = []
    permission_classes = []

    def get(self, request, format=None):
        phone_number = request.query_params.get('phoneNumber')
        # 手机号码为空
        if not phone_number:
            response = error_result(code=1005, msg="手机号码无效")
            return Response(response)
        else:
            phone_rule = '[1][3,4,5,7,8,9][0-9]{9}$'
            if not re.match(phone_rule, phone_number):
                return Response(error_result(code=1005, msg="手机号码格式错误"))
            # 手机号码已经被注册
            phone_server = User.objects.filter(phone=phone_number).last()
            if phone_server:
                response = error_result(code=1006, msg="手机号码已经被注册")
                return Response(response)
        response = error_result(code=200, results=True, msg="手机号码可用")
        return Response(response)


# 检测短信息验证码是否可用，要求手机号码所在的cache码存在
class CheckPhoneCode(APIView):
    """
    get:
    不需要参数，返回验证结果
    """
    authentication_classes = []
    permission_classes = []

    def get(self, request, format=None):
        phone_number = request.query_params.get('phoneNumber')
        phone_code = request.query_params.get('phoneCode')
        # 手机号码为空
        if not phone_number or not phone_code:
            return Response(error_result(code=1005, results='no', msg="手机号码及验证码不能空"))
        phone_code_cache = cache.get(phone_number)
        if not phone_code_cache:
            return Response(error_result(code=1011, results="no", msg="验证码错误"))
        if phone_code != phone_code_cache:
            return Response(error_result(code=1011, results="no", msg="验证码错误"))
        return Response(error_result(code=200, results=True, msg="手机号码可用"))


# 检测姓名是否可用，即用户名重名检测
class CheckRealNameUsableAPIView(APIView):
    """
    get:
    不需要参数，返回验证结果
    """
    authentication_classes = []
    permission_classes = []

    def get(self, request, format=None):
        real_name = request.query_params.get('real_name')
        # 用户名为空
        if not real_name:
            response = error_result(code=1005, results={}, msg="用户名不能空")
            return Response(response)
        else:
            # 用户名已经被注册
            server_obj = User.objects.filter(username=real_name)
            if len(server_obj) > 0:
                response = error_result(code=1006, results={}, msg="用户名已经被注册")
                return Response(response)
        response = error_result(code=200, results=True, msg="该姓名可用")
        return Response(response)


# 用户激活审核管理
class AccountManagerModelViewSet(CustomNoQuestionsModelViewSet):
    """
    会员激活审核与等级审核
    """
    queryset = UserActivateApplication.objects.all()
    serializer_class = UserApplicationModelSerializer
    filter_fields = ('type', 'user')
    pagination_class = SmallPage
    ordering_fields = ('-add_date', 'type')

    # 用于管理员获取用户激活申请单，天数为0或者空，则获取所有记录
    def list(self, request, *args, **kwargs):
        try:
            query_days = request.query_params.get('days')
            if query_days is None:
                applications = self.get_queryset()
            elif int(query_days) == 0:
                applications = self.get_queryset()
            else:
                current_date = date.today()
                past_date = current_date - timedelta(days=query_days)
                applications = UserActivateApplication.objects.filter(add_date__gt=past_date)
            page = self.paginate_queryset(applications)
            serializer = self.get_serializer(page, many=True)
            # print(serializer.data)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg=data_parameters_error, results={}))

    def create(self, request, *args, **kwargs):
        try:
            user_id = request.user.id
            application = UserActivateApplication.objects.filter(user__id=user_id)
            if len(application) > 0:
                return Response(error_result(code=1021, msg="对不起，你已经申请过了", results='no'))
            request.data['user'] = user_id
            request.data['status'] = 0
            serializer = self.get_serializer(data=request.data)
            if not serializer.is_valid():
                return Response(error_result(code=406, msg=data_error_text, results=serializer.errors))
            else:
                self.perform_create(serializer)
                return Response(error_result(code=200, msg=data_add_text, results=serializer.data))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg="错误", results='no'))

    def update(self, request, *args, **kwargs):
        try:
            application_id = request.data['id']
            application = UserActivateApplication.objects.filter(pk=application_id).first()
            if not application:
                return Response(error_result(code=1021, msg="申请的号码不存在", results='no'))
            application_user = application.user
            is_active = application_user.is_active
            operate = request.data['operate']
            if operate == 'agree' and is_active:
                return Response(error_result(code=200, msg="该会员的状态已经是激活", results='Yes'))
            elif operate == 'reject' and not is_active:
                return Response(error_result(code=200, msg="该会员已经是被禁用", results='Yes'))
            elif operate == 'agree' and not is_active:
                application_user.is_active = True
                application.status = 1
                application_user.save()
                application.save()
            elif operate == 'reject' and is_active:
                application_user.is_active = False
                application.status = 2
                application_user.save()
                application.save()
            query_days = int(request.data['days'])
            if not query_days:
                query_days = 7
            current_date = date.today()
            past_date = current_date - timedelta(days=query_days)
            applications = UserActivateApplication.objects.filter(add_date__gt=past_date)
            page = self.paginate_queryset(applications)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return Response(error_result(code=200, results=serializer.data, total=len(applications)))
            serializer = self.get_serializer(applications, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))

        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg="错误", results='no'))

    # 手机号码和姓名搜索记录
    @action(methods=['get'], detail=False)
    def search(self, request):
        query_key = request.query_params['user']
        applications = UserActivateApplication.objects.filter(
            Q(user__real_name__contains=query_key) | Q(user__phone__contains=query_key))
        if not applications:
            return Response(error_result(code=1099, msg=data_query_fail, results='no'))
        page = self.paginate_queryset(applications)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))
        serializer = self.get_serializer(applications, many=True)
        return Response(error_result(code=200, results=serializer.data, total=len(applications)))


class UserVIPApplicationManagerModelViewSet(CustomNoQuestionsModelViewSet):
    """
    会员激活审核与等级审核
    """
    queryset = UserVIPApplication.objects.all()
    serializer_class = UserVIPApplicationModelSerializer
    filter_fields = ('VIP_grade', 'user')
    pagination_class = SmallPage
    ordering_fields = ('-add_date', 'VIP_grade')

    def list(self, request, *args, **kwargs):
        try:
            query_days = request.query_params.get('days')
            if not query_days:
                applications = self.get_queryset()
            elif int(query_days) == 0:
                applications = self.get_queryset()
            else:
                query_days = int(query_days)
                current_date = date.today()
                past_date = current_date - timedelta(days=query_days)
                applications = UserVIPApplication.objects.filter(add_date__gt=past_date)
            page = self.paginate_queryset(applications)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return Response(error_result(code=200, results=serializer.data, total=len(applications)))
            serializer = self.get_serializer(applications, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg=data_parameters_error, results='no'))

    def create(self, request, *args, **kwargs):
        try:
            # 7天内不能重复申请
            user = request.user
            current_date = date.today()
            past_date = current_date - timedelta(days=7)
            applications = UserVIPApplication.objects.filter(
                Q(add_date__gt=past_date) & Q(status=0) & Q(user__id=user.id))
            if applications:
                return Response(error_result(code=1021, msg="对不起，你已经申请过了，请联系管理员通过审核", results='no'))
            grade = request.data.get('grade')
            if user.VIP >= grade:
                return Response(error_result(code=1021, msg="对不起，申请的会员等级不能低于或等于当前等级", results='no'))
            request.data['user'] = user.id
            request.data['status'] = 0
            serializer = self.get_serializer(data=request.data)
            if not serializer.is_valid():
                return Response(error_result(code=406, msg=data_error_text, results=serializer.errors))
            else:
                self.perform_create(serializer)
                return Response(error_result(code=200, msg=data_add_text, results=serializer.data))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg="错误", results='no'))

    def update(self, request, *args, **kwargs):

        try:
            application_id = request.data['id']
            application = UserVIPApplication.objects.filter(pk=application_id).first()
            if not application:
                return Response(error_result(code=1021, msg="申请的号码不存在", results='no'))
            application_user = application.user
            vip_grade_apply = int(request.data.get('grade'))
            if vip_grade_apply <= 0:
                return Response(error_result(code=1099, msg="申请的等级错误", results='No'))
            # 一天内不能重复申请
            current_date = date.today()
            past_date = current_date - timedelta(days=1)
            applications = UserActivateApplication.objects.filter(add_date__gt=past_date)
            if applications:
                return Response(error_result(code=1099, msg="一天内不能重复申请，请联系管理员", results='No'))
            operate = request.data.get('operate')
            if operate == 'agree':
                application_user.VIP = vip_grade_apply
                application.status = 1
                application_user.save()
                application.save()
            elif operate == 'reject':
                application.status = 2
                application.save()
            query_days = request.data.get('days')
            if not query_days:
                query_days = 7
            else:
                query_days = int(query_days)
            current_date = date.today()
            past_date = current_date - timedelta(days=query_days)
            applications = UserActivateApplication.objects.filter(add_date__gt=past_date)
            page = self.paginate_queryset(applications)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return Response(error_result(code=200, results=serializer.data, total=len(applications)))
            serializer = self.get_serializer(applications, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg="错误", results='no'))

    # 手机号码和姓名搜索记录
    @action(methods=['get'], detail=False)
    def search(self, request):
        query_key = request.query_params['user']
        applications = UserVIPApplication.objects.filter(
            Q(user__real_name__contains=query_key) | Q(user__phone__contains=query_key))
        if not applications:
            return Response(error_result(code=1099, msg=data_query_fail, results='no'))
        page = self.paginate_queryset(applications)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))
        serializer = self.get_serializer(applications, many=True)
        return Response(error_result(code=200, results=serializer.data, total=len(applications)))


class UserNicknameApplicationModelViewSet(CustomNoQuestionsModelViewSet):
    """
    用户的查增删改
    """
    queryset = UserNicknameApplication.objects.all()
    serializer_class = UserNicknameApplicationModelSerializer
    filter_fields = ('user',)
    pagination_class = SmallPage
    ordering_fields = ('-add_date',)

    def create(self, request, *args, **kwargs):
        try:
            # 7天内不能重复申请
            user = request.user
            current_date = date.today()
            past_date = current_date - timedelta(days=7)
            applications = UserNicknameApplication.objects.filter(
                Q(add_date__gt=past_date) & Q(status=0) & Q(user__id=user.id))
            if applications:
                return Response(error_result(code=1021, msg="对不起，你已经申请过了，请联系管理员通过审核", results='no'))
            nickname = request.data.get('nickname')
            if not nickname:
                return Response(error_result(code=1021, msg="对不起，昵称不合格！", results='no'))
            request.data['user'] = user.id
            request.data['status'] = 0
            serializer = self.get_serializer(data=request.data)
            if not serializer.is_valid():
                return Response(error_result(code=406, msg=data_error_text, results=serializer.errors))
            else:
                self.perform_create(serializer)
                return Response(error_result(code=200, msg=data_add_text, results=serializer.data))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg="错误", results='no'))

    def list(self, request, *args, **kwargs):
        try:
            query_days = request.query_params.get('days')
            if not query_days:
                applications = self.get_queryset()
            elif int(query_days) == 0:
                applications = self.get_queryset()
            else:
                query_days = int(query_days)
                current_date = date.today()
                past_date = current_date - timedelta(days=query_days)
                applications = UserNicknameApplication.objects.filter(add_date__gt=past_date)
            page = self.paginate_queryset(applications)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return Response(error_result(code=200, results=serializer.data, total=len(applications)))
            serializer = self.get_serializer(applications, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg=data_parameters_error, results='no'))

    def update(self, request, *args, **kwargs):
        try:
            application_id = request.data['id']
            application = UserNicknameApplication.objects.filter(pk=application_id).first()
            if not application:
                return Response(error_result(code=1021, msg="申请的表单不存在", results='no'))
            application_user = application.user
            nickname_new = application.nickname
            operate = request.data.get('operate')
            if operate == 'agree' and application.status != 1:
                application_user.nickname = nickname_new
                application.status = 1
                application_user.save()
                application.save()
            elif operate == 'reject' and application.status != 2:
                application.status = 2
                application.save()
            else:
                return Response(error_result(code=1099, msg="此操作没必要", results='No'))
            query_days = request.data.get('days')
            if not query_days:
                query_days = 7
            else:
                query_days = int(query_days)
            current_date = date.today()
            past_date = current_date - timedelta(days=query_days)
            applications = UserNicknameApplication.objects.filter(add_date__gt=past_date)
            page = self.paginate_queryset(applications)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return Response(error_result(code=200, results=serializer.data, total=len(applications)))
            serializer = self.get_serializer(applications, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg="错误", results='no'))

    # 手机号码和姓名搜索记录, 如果没有参数user，那就查询全部记录
    @action(methods=['get'], detail=False)
    def search(self, request):
        query_key = request.query_params.get('user')
        if query_key:
            applications = UserNicknameApplication.objects.filter(
                Q(user__real_name__contains=query_key) | Q(user__phone__contains=query_key))
            if not applications:
                return Response(error_result(code=1099, msg=data_query_fail, results='no'))
        else:
            applications = UserNicknameApplication.objects.all()
        page = self.paginate_queryset(applications)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(applications)))
        serializer = self.get_serializer(applications, many=True)
        return Response(error_result(code=200, results=serializer.data, total=len(applications)))


class UserModelViewSet(CustomNoQuestionsModelViewSet):
    """
    用户数据
    """
    queryset = User
    serializer_class = UserSerializer
    ordering_fields = ('challenge_score', 'bank_point')
    pagination_class = SmallPage

    # 关联一个用户和班级, 参数为用户id和班级id
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsOwnerPermission]
            )
    def link_user_class(self, request, *args, **kwargs):
        try:
            class_id = request.data['class_id']
            user_list = request.data['user_list']
            if isinstance(user_list, list):
                if len(user_list) == 0:
                    return Response(error_result(code=1099, results='空数组', msg='空数组'))
            else:
                return Response(error_result(code=1098, results='no', msg='用户必须是数组格式'))
            new_list = []
            for user in user_list:
                user_class_dict = {'user': user, 'class_grade': class_id}
                new_list.append(user_class_dict)
            serializer = UserOfClassModelSerializer(data=new_list, many=True)
            if not serializer.is_valid():
                print("序列化错误:", serializer.errors)
                return Response(error_result(code=406, msg=serializer.errors, results=data_error_text))
            serializer.save()
            return Response(error_result(code=200, msg="恭喜，添加班级成功！", results='OK'))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 上传csv，返回名单（用于注册教师用户和学生用户，因为涉及手机，方法略有不同）。注意：没有实际注册
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin]
            )
    def upload_csv(self, request, *args, **kwargs):
        try:
            from utils.SaveImage import save_csv
            file = request.FILES.get('upload_file')
            file_path, file_path_no_https, result_flag = save_csv(file)
            if not result_flag:
                return Response(error_result(code=1099, results='no'))
            name_list = []
            error_list = []
            # 打开CSV文件
            with open(file_path_no_https, 'r', encoding='utf-8', errors='ignore') as csv_file:
                # 创建CSV读取器对象
                csv_reader = csv.reader(csv_file)
                # 跳过第一行（表头）
                next(csv_reader)
                # 从第二行开始遍历
                for item in csv_reader:
                    name_dic = {'index': item[0], 'username': item[1]}
                    if item[1] == '':
                        error_list += item[0]+'姓名错误;'
                        continue
                    # 第3列如果提交的是1开头，即手机号码
                    if item[2][0] == '1':
                        # 手机号码格式
                        pattern = re.compile(r'^1[3-9]\d{9}$')
                        if not re.match(pattern, item[2]):
                            error_list.append('序号' + item[0]+'手机号码格式错误;')
                            continue
                        # 手机号码是否已经注册过了
                        user_server = self.get_queryset().objects.filter(phone=item[2][0])
                        if len(user_server) > 0:
                            error_list.append('序号' + item[0] + '手机号码已经存在;')
                            continue
                        name_dic['phone'] = item[2]
                    # 第3列如果提交的是2开头，即学生的学号
                    elif item[2][0] == '2':
                        # 学号格式
                        pattern = re.compile(r'^\d{8}$')
                        if not re.match(pattern, item[2]):
                            error_list.append('序号' + item[0] + '学号格式错误;')
                            continue
                        # 学号是否已经注册过了
                        user_server = self.get_queryset().objects.filter(Q(number=item[2]) & Q(username=item[1]))
                        if len(user_server) > 0:
                            error_list.append('序号' + item[0] + '姓名、学号已经存在;')
                            continue
                        name_dic['number'] = item[2]
                    name_list.append(name_dic)
            if len(error_list) > 0:
                return Response(error_result(code=1099, results=error_list, msg='名单为空'))
            return Response(error_result(code=200, results=name_list))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 上传csv，返回名单（用于注册教师用户和学生用户，因为涉及手机，方法略有不同）。注意：此版本检测是否与班级关联过
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin]
            )
    def upload_csv_check(self, request, *args, **kwargs):
        try:
            from utils.SaveImage import save_csv
            file = request.FILES.get('upload_file')
            file_path, file_path_no_https, result_flag = save_csv(file)
            if not result_flag:
                return Response(error_result(code=1099, results='no'))
            name_list = []
            error_list = []
            class_name = ''
            # 打开CSV文件
            with open(file_path_no_https, 'r', encoding='utf-8', errors='ignore') as csv_file:
                # 创建CSV读取器对象
                csv_reader = csv.reader(csv_file)
                # 跳过第一行（表头）
                next(csv_reader)
                # 从第二行开始遍历
                for item in csv_reader:
                    if class_name == '' and item[2] != '':
                        class_name = item[3]
                    name_dic = {'index': item[0], 'username': item[1]}
                    # 检测第2列第姓名是否注册过了，存在重名
                    user_name = item[1]
                    user_server_obj = User.objects.filter(username=user_name)
                    if len(user_server_obj) > 0:
                        error_list.append('序号' + item[0] + item[1] + '用户名已经用过，建议姓名尾部添加班级学号!')
                    if item[1] == '':
                        error_list += item[0] + '姓名错误;'
                        continue
                    # 第3列如果提交的是1开头，即手机号码
                    if item[2][0] == '1':
                        # 手机号码格式
                        pattern = re.compile(r'^1[3-9]\d{9}$')
                        if not re.match(pattern, item[2]):
                            error_list.append('序号' + item[0] + item[1] + '手机号码格式错误!')
                            continue
                        # 手机号码是否已经注册过了
                        user_server = self.get_queryset().objects.filter(phone=item[2][0])
                        if len(user_server) > 0:
                            error_list.append('序号' + item[0] + item[1] + '手机号码已经存在！')
                            continue
                        name_dic['phone'] = item[2]
                    # 第3列如果提交的是2开头，即学生的学号
                    elif item[2][0] == '2':
                        # 学号格式
                        pattern = re.compile(r'^\d{8}$')
                        if not re.match(pattern, item[2]):
                            error_list.append('序号 ' + item[0] + item[1] + ' 学号格式错误;')
                            continue
                        # 学号是否已经注册过了
                        user_server = self.get_queryset().objects.filter(Q(number=item[2]) & Q(username=item[1]))
                        if len(user_server) > 0:
                            error_list.append('序号' + item[0] + " " + item[1] + '， 学号已经注册！建议手工关联该学生')
                            continue
                        user_class_server = UserOfClass.objects.filter(Q(user__number=item[2]) &
                                                                       Q(class_grade__name=class_name))
                        # print('user_class_server：', user_class_server)
                        if len(user_class_server) > 0:
                            error_list.append('序号' + item[0] + item[1] + '已经关联该班级了;')
                            continue
                        name_dic['number'] = item[2]
                    name_list.append(name_dic)
            if len(error_list) > 0:
                return Response(error_result(code=1099, results=error_list, msg='名单为空'))
            return Response(error_result(code=200, results=name_list))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 批量导入名单注册会员（教师）
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin]
            )
    def create_many_user_by_file(self, request, *args, **kwargs):
        try:
            name_list = request.data['name_list']
            if isinstance(name_list, list):
                if len(name_list) == 0:
                    return Response(error_result(code=1099, results='空数组', msg='空数组'))
            else:
                print(f"{name_list} 不是一个列表。")
                return Response(error_result(code=1099, results='必须提交数组', msg='必须提交数组'))
            for i in range(len(name_list)):
                name_list[i]['password'] = make_password("123456")
                name_list[i]['real_name'] = name_list[i]['username']
                name_list[i]['nickname'] = name_list[i]['username']
                name_list[i]['is_active'] = False
                name_list[i]['is_teacher'] = True

            serializer = self.get_serializer(data=name_list, many=True)
            if not serializer.is_valid():
                print('反序列化错误：', serializer.errors)
                return Response(error_result(code=1099, results=serializer.errors, msg='序列化错误'))
            serializer.save()
            username_company = Company.objects.first().president
            user_company = User.objects.get(username=username_company)
            for user in serializer.instance:
                create_customer_bank_point_log_change.delay(receiver=user.pk,
                                                            operator=user_company.pk,
                                                            point_amount=register_award_points,
                                                            remarks='注册新账号')
                activate_application_dic = {'user': user.id, 'status': 0}
                activate_serializer = UserApplicationModelSerializer(data=activate_application_dic)
                if not activate_serializer.is_valid():
                    return Response(error_result(code=201, msg="注册成功，请联系管理员激活账号", results=activate_serializer.errors))
                else:
                    activate_serializer.save()
            return Response(error_result(code=200))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 解除用户与班级的关联
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            )
    def cancel_link(self, request, *args, **kwargs):
        try:
            user_id = request.data['user_id']
            class_id = request.data['class_id']
            class_server_obj = ClassGrade.objects.get(id=class_id)
            class_server_obj.user.remove(user_id)
            return Response(error_result(code=200))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 批量导入名单数组（教师或学生），注册用户即持久化到数据库，并将用户批量关联到班级，注：直接激活用户
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin]
            )
    def create_many_user_link_class(self, request, *args, **kwargs):
        with transaction.atomic():
            sid = transaction.savepoint()
            try:
                class_grade = request.data['class_id']
                name_list = request.data['user_list']
                if isinstance(name_list, list):
                    if len(name_list) == 0:
                        return Response(error_result(code=1099, results='空数组', msg='空数组'))
                else:
                    print(f"{name_list} 不是一个列表。")
                    return Response(error_result(code=1099, results='必须提交数组', msg='必须提交数组'))
                class_student_list = []
                for i in range(len(name_list)):
                    del(name_list[i]['index'])
                    name_list[i]['password'] = make_password("123456")
                    name_list[i]['real_name'] = name_list[i]['username']
                    name_list[i]['nickname'] = name_list[i]['username']
                    name_list[i]['is_active'] = True
                    class_student_list.append({'class_grade': class_grade})
                # 批量持久化用户到User数据表
                serializer_user = self.get_serializer(data=name_list, many=True)
                if not serializer_user.is_valid():
                    print('反序列化错误：', serializer_user.errors)
                    transaction.savepoint_rollback(sid)
                    return Response(error_result(code=1098, results=serializer_user.errors, msg='序列化错误'))
                serializer_user.save()

                # 关联班级
                for item in serializer_user.instance:
                    class_student_list[i]['user'] = item.id
                class_server_obj = ClassGrade.objects.get(id=class_grade)
                class_server_obj.user.add(*serializer_user.instance)

                # 添加库币
                username_company = Company.objects.first().president
                user_company = User.objects.get(username=username_company)
                for user in serializer_user.instance:
                    create_customer_bank_point_log_change.delay(receiver=user.pk,
                                                                operator=user_company.pk,
                                                                point_amount=register_award_points,
                                                                remarks='注册新账号')
                return Response(error_result(code=200))
            except Exception as e:
                print('Exception:', e)
                transaction.savepoint_rollback(sid)
                return Response(error_result(code=500))

    # 修改密码
    def update(self, request, *args, **kwargs):
        try:
            password_old = request.data["password_old"]
            password_new = request.data["password_new"]
            password2_new = request.data["password2_new"]
            # 效验新密码是否符合要求
            if password_new != password2_new:
                return Response(error_result(code=1003))
            if len(password_new) > 20 or len(password_new) < 8:
                return Response(error_result(code=1003))
            # 获得请求用户
            pk = kwargs.get('pk')
            user = User.objects.filter(pk=pk)
            if len(user) <= 0:
                return Response(error_result(code=1003, results='no', msg='用户异常，请联系管理员'))
            user = user.first()
            # 检查原始密码是否正确
            if not check_password(password_old, user.password):
                return Response(error_result(code=401, results='no', msg='原始密码错误，无法修改'))
            # 修改密码为新密码
            user.set_password(password_new)
            user.save()
            # 返回数据
            return Response(error_result(code=200, results='yes'))
        except Exception as E:
            print(E)
            return Response(error_result(code=500, msg="错误", results='no'))

    # 用户自己申请重置密码
    @action(methods=['patch'],
            detail=True,
            authentication_classes=[],
            permission_classes=[]
            )
    def reset_password(self, request, *args, **kwargs):
        try:
            phone_number = kwargs['pk']
            phone_rule = '[1][3,4,5,7,8,9][0-9]{9}$'
            if not re.match(phone_rule, phone_number):
                return Response(error_result(code=1005, msg="手机号码格式错误"))
            obj_server = self.get_queryset().objects.filter(phone=phone_number)
            if not obj_server:
                return Response(error_result(code=1003, msg="手机号码错误", results='no'))
            client_code = request.data.get('clientCode')
            captcha_code = request.data.get('captchaCode')
            captcha_code = captcha_code.upper()
            phone_code = request.data.get('phoneCode')
            server_client_code = cache.get(captcha_code)
            # 前两次的验证码错误，防止跳过前2个机器人验证，而直接发送验证码注册
            if server_client_code != str(client_code):
                return Response(error_result(code=1015, msg='你是机器人吗？', results='no'))
            # 短信号码不为空
            if not phone_code:
                return Response(error_result(code=1010, msg='短信号码不能空', results='no'))
            server_phone_code = cache.get(phone_number)
            # 短信验证码不存在, 可能更换过手机号码
            if not server_phone_code:
                return Response(error_result(code=1017, msg='短信号码错误', results='no'))
            # 验证码错误或者已经过期
            if server_phone_code != phone_code:
                return Response(error_result(code=1017, msg='短信号码错误', results='no'))
            # 检测验证码已经存在于服务器，且未过期，则完成密码重置
            password = make_password("123456")
            user_modify_dic = {'password': password}
            obj_server = obj_server.first()
            serializer = UserSerializer(instance=obj_server, data=user_modify_dic, partial=True)
            if not serializer.is_valid():
                return Response(error_result(code=406, msg=data_error_text, results=serializer.errors))
            serializer.save()
            return Response(error_result(code=200, msg='你的密码是123456，请及时修改密码', results='no'))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 查询手机号码是否存在
    @action(methods=['get'],
            detail=False,
            authentication_classes=[],
            permission_classes=[]
            )
    def phone_number_exit(self, request):
        try:
            phone_number = request.query_params['phoneNumber']
            user_list = User.objects.filter(phone=phone_number)
            if user_list:
                user_obj = user_list.first()
                serializer = UserSimpleModelSerializer(user_obj)
                return Response(error_result(code=200, results=serializer.data, msg='该手机号码存在'))
            else:
                return Response(error_result(code=200, results=False, msg='该手机号码不存在'))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 按照得分降序排序的前100名
    @action(methods=['get'], detail=False, url_path='ranking')
    def ranking(self, request):
        try:
            user_list = User.objects.all().order_by('-challenge_score')[:2]
            total = len(user_list)
            if not user_list:
                return Response(error_result(code=1099))
            page = self.paginate_queryset(user_list)
            serializer = UserSimpleModelSerializer(page, many=True)
            return Response(error_result(code=200, results=serializer.data, total=total))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 按照得分降序排序的前100名
    @action(methods=['get'], detail=False, url_path='my_ranking')
    def my_ranking(self, request):
        try:
            # 从数据库获取最新的排名信息
            user_pk = request.user.pk
            user_myself = self.get_queryset().objects.get(pk=user_pk)
            my_score = user_myself.challenge_score
            user_list = User.objects.filter(challenge_score__gt=my_score)
            my_ranking = 1
            if user_list:
                my_ranking = len(user_list) + 1
            return Response(error_result(code=200, results=my_ranking))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 修改自己的密码
    @action(methods=['put'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsOwnerPermission]
            )
    def change_password(self, request, *args, **kwargs):
        try:
            password = request.data['password']
            password = make_password(password)
            user_modify_dic = {'password': password}
            pk = request.user.id
            obj_server = self.get_queryset().objects.filter(pk=pk)
            if not obj_server:
                return Response(error_result(code=1099))
            obj_server = obj_server.first()
            serializer = UserSerializer(instance=obj_server, data=user_modify_dic, partial=True)
            if not serializer.is_valid():
                return Response(error_result(code=406, msg=data_error_text, results=serializer.errors))
            serializer.save()
            return Response(error_result(code=200))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 修改自己的基本资料：昵称（不含密码）
    @action(methods=['put'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsOwnerPermission]
            )
    def modify_nickname(self, request, *args, **kwargs):
        try:
            nickname = request.data['nickname']
            user_modify_dic = {'nickname': nickname}
            pk = request.user.id
            obj_server = self.get_queryset().objects.filter(pk=pk)
            if not obj_server:
                return Response(error_result(code=1099))
            obj_server = obj_server.first()
            serializer = UserSerializer(instance=obj_server, data=user_modify_dic, partial=True)
            if not serializer.is_valid():
                return Response(error_result(code=406, msg=data_error_text, results=serializer.errors))
            serializer.save()
            return Response(error_result(code=200))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 初始化密码为123456
    @action(methods=['put'],
            detail=False,
            authentication_classes=[Authentication],
            # permission_classes=[IsAdmin]
            )
    def init_password(self, request, *args, **kwargs):
        try:
            pk = request.data['id']
            user_modify_dic = {'password': make_password("123456")}
            obj_server = self.get_queryset().objects.filter(pk=pk)
            if not obj_server:
                return Response(error_result(code=1099))
            obj_server = obj_server.first()
            serializer = UserSerializer(instance=obj_server, data=user_modify_dic, partial=True)
            if not serializer.is_valid():
                print('反序列化错误', serializer.errors)
                return Response(error_result(code=1099, msg=data_error_text, results=serializer.errors))
            serializer.save()
            return Response(error_result(code=200))
        except Exception as e:
            print('exception:', e)
            return Response(error_result(code=500))

    # 管理员设置用户为教师类型
    @action(methods=['put'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin]
            )
    def set_teacher(self, request, *args, **kwargs):
        try:
            pk = request.data['id']
            user_modify_dic = {'is_teacher': True}
            obj_server = self.get_queryset().objects.filter(pk=pk)
            if not obj_server:
                return Response(error_result(code=1099))
            obj_server = obj_server.first()
            serializer = UserSerializer(instance=obj_server, data=user_modify_dic, partial=True)
            if not serializer.is_valid():
                return Response(error_result(code=1099, msg=data_error_text, results=serializer.errors))
            serializer.save()
            return Response(error_result(code=200))
        except Exception as e:
            print('exception:', e)
            return Response(error_result(code=500))

    # 修改自己的基本资料：头像（未完成）
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            permission_classes=[IsOwnerPermission]
            )
    def modify_avatar(self, request, *args, **kwargs):
        try:
            images = request.FILES['images']
            result_boolean, images_url, images_path = SaveImage.save_image(images)
            if not result_boolean:
                return Response(error_result(code=1099, msg='头像上传错误', results='no'))
            user_modify_dic = {'avatar': images_url}
            pk = request.user.id
            obj_server = self.get_queryset().objects.filter(pk=pk)
            if not obj_server:
                return Response(error_result(code=1099))
            obj_server = obj_server.first()
            serializer = UserSerializer(instance=obj_server, data=user_modify_dic, partial=True)
            if not serializer.is_valid():
                return Response(error_result(code=406, msg=data_error_text, results=serializer.errors))
            serializer.save()
            return Response(error_result(code=200))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 获取自己的用户信息
    @action(methods=['get'],
            detail=False,
            )
    def myself_info(self, request):
        try:
            # 从数据库获取最新的个人信息
            user_pk = request.user.pk
            user_myself = self.get_queryset().objects.filter(pk=user_pk)
            if not user_myself:
                return Response(error_result(code=1099))
            serializer = UserSimpleModelSerializer(user_myself.first())
            return Response(error_result(code=200, results=serializer.data))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 根据用户名获取用户数据
    @action(methods=['get'],
            detail=False,
            authentication_classes=[Authentication],
            )
    def get_user_by_username(self, request):
        try:
            # 从数据库获取最新的个人信息
            username = request.query_params.get('username')
            user_server_obj = self.get_queryset().objects.filter(username=username)
            if not user_server_obj:
                return Response(error_result(code=1099, results='该用户不存在！'))
            serializer = UserSimpleModelSerializer(user_server_obj.first())
            return Response(error_result(code=200, results=serializer.data))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 补充库币
    @action(methods=['get'],
            detail=False,
            authentication_classes=[],
            permission_classes=[]
            # authentication_classes=[Authentication],
            # permission_classes=[IsAdmin]
            )
    def supply_point(self, request, *args, **kwargs):
        try:
            obj_server_list = self.get_queryset().objects.all()
            if not obj_server_list:
                return Response(error_result(code=1099))
            for obj_server in obj_server_list:
                bank_point = obj_server.bank_point
                supply_amount = 0
                flag = False
                while bank_point < 0:
                    supply_amount += 200
                    bank_point += supply_amount
                if 0 <= bank_point <= 100:
                    supply_amount += 200
                    flag = True
                elif 100 < bank_point <= 200:
                    supply_amount += 100
                    flag = True
                elif 300 > bank_point > 200:
                    supply_amount += 50
                    flag = True
                if flag:
                    username_company = Company.objects.first().president
                    user_company = User.objects.get(username=username_company)
                    create_customer_bank_point_log_change.delay(receiver=obj_server.pk,
                                                                operator=user_company.pk,
                                                                point_amount=supply_amount,
                                                                remarks='管理员直接打款')
            return Response(error_result(code=200))
        except Exception as e:
            print('exception:', e)
            return Response(error_result(code=500))


# 发送手机短信验证码，用于忘记密码时重置密码接收短信息
# 第3次发送接收前端的rand1和rand2，如果验证通过，发送手机短信，要求该手机号码已注册
class SendPhoneCodeView(CacheResponseMixin, APIView):
    """
    发送接收前端的rand1和rand2，如果验证通过，发送手机短信,返回是否发送成功
    """
    permission_classes = []
    authentication_classes = []

    def get(self, request):
        try:
            phone_number = request.query_params.get('phoneNumber')
            client_code = request.query_params.get('clientCode')
            captcha_code = request.GET.get('captchaCode')
            captcha_code = captcha_code.upper()
            server_client_code = cache.get(captcha_code)
            if server_client_code != client_code:
                response = error_result(code=1015, msg='随机码验证失败，请刷新网页再试试')
                return Response(response)
            if not phone_number:
                return Response(error_result(code=1004, msg='手机号码是必填的'))
            # 如果手机或者用户名号码不合法
            mobile_pat = re.compile(r'^1[3-9]\d{9}$')
            res = re.search(mobile_pat, phone_number)
            if not res:
                return Response(error_result(code=1004, msg='手机号码不合法'))
            # 如果手机或者用户名号码合法，查看手机号是否已经存在与用户中
            had_register_phone = User.objects.filter(phone=phone_number)
            if not had_register_phone:
                return Response(error_result(code=1004, msg='手机号码不存在', results='no'))
            server_phone_code = cache.get(phone_number)
            # 如果这个手机号已经发送过
            if server_phone_code:
                last_send_time = cache.get('last_time' + phone_number)
                if last_send_time and last_send_time > (datetime.datetime.now() - datetime.timedelta(minutes=1)):
                    return Response(error_result(code=1018, msg='不足一分钟', results='no'))
            # 生成随机数验证码,设定验证码的过期时间为5分钟以后,发送验证码，存入缓存
            phone_code = generate_random_code(type_code=2, length=6)
            cache.set(phone_number, phone_code, 5 * 60)
            cache.set('last_time' + phone_number, datetime.datetime.now(), 5 * 60)
            # 调用发送模块
            mss_status = Huyiwuxian.send_message_by_huyiwuxian(mobile=phone_number, message_code=phone_code)
            response = error_result(code=200, results=mss_status, msg='验证码已经发送，请注意查收')
            return Response(response)
        except Exception as e:
            print(e)
            return Response(error_result(code=500))


class NotificationModelViewSet(CustomNoQuestionsModelViewSet):
    """
    通知的查增删改
    """
    queryset = Notification
    serializer_class = NotificationModelSerializer
    filter_fields = ('add_date',)
    pagination_class = SmallPage
    ordering_fields = ('-add_date',)

    # 查询自己的所有通知
    @action(methods=['get'],
            detail=False,
            url_path='only_owner',
            authentication_classes=[Authentication],
            permission_classes=[IsOwnerPermission])
    def only_owner(self, request):
        try:
            objs = self.get_queryset().objects.filter(user__pk=request.user.id)
            serializer = self.get_serializer(data=objs)
            if serializer.is_valid(raise_exception=False):
                return Response(error_result(code=200, results=serializer.data))
            else:
                return Response(error_result(code=1099, results=serializer.errors))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 修改自己的通知状态为已读
    @action(methods=['patch'],
            detail=True,
            url_path='set_own_has_read',
            authentication_classes=[Authentication],
            permission_classes=[IsOwnerPermission])
    def set_own_has_read(self, request, *args, **kwargs):
        try:
            pk = kwargs['pk']
            server_data = self.get_queryset().objects.filter(Q(user__pk=request.user.id) & Q(pk=pk))
            modify_data = {'status': 0}
            serializer = self.get_serializer(instance=server_data, data=modify_data, partial=True)
            if serializer.is_valid(raise_exception=False):
                return Response(error_result(code=200, results=serializer.data))
            else:
                return Response(error_result(code=1099, results=serializer.errors))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 生成通知
    @action(methods=['post'],
            detail=False,
            url_path='create_notification',
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin])
    def create_notification(self, request, *args, **kwargs):
        try:
            user_id = request.data['user_id']
            user = User.objects.get(id=user_id)
            request.data['user'] = user
            del request.data['user_id']
            serializer = self.get_serializer(data=request.data)
            if serializer.is_valid(raise_exception=False):
                serializer.save()
                return Response(error_result(code=200, results="ok"))
            else:
                return Response(error_result(code=1099))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))


class BankPointLogModelViewSet(CustomNoQuestionsModelViewSet):
    queryset = CustomerBankPointChangeLog
    serializer_class = CustomerBankPointChangeLogModelSerializer
    filter_fields = ('receiver', 'operator')
    pagination_class = SmallPage
    ordering_fields = ('-add_time',)

    # 管理员手工生成交易
    @action(methods=['post'],
            detail=False,
            url_path='create_bank_point_change',
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin])
    def create_bank_point_change(self, request, *args, **kwargs):
        try:
            receiver_id = request.data['receiver_id']
            receiver = User.objects.get(id=receiver_id)
            request.data['receiver'] = receiver
            del request.data['receiver_id']
            operator_id = request.data['operator_id']
            operator = User.objects.get(id=operator_id)
            request.data['operator'] = operator
            del request.data['operator_id']
            serializer = self.get_serializer(request.data)
            if serializer.is_valid(raise_exception=False):
                return Response(error_result(code=200, results="ok"))
            else:
                return Response(error_result(code=1099))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 获取自己名下的收支情况，默认是收支两者情况
    @action(methods=['get'],
            detail=False,
            )
    def get_income_expense_for_owner(self, request):
        try:
            payment_type = request.query_params.get('payment_type', None)
            if payment_type is None:
                server_obj_list = self.get_queryset().objects.filter(Q(receiver__id=request.user.id) |
                                                                     Q(operator__id=request.user.id))
            elif payment_type == 'income':
                server_obj_list = self.get_queryset().objects.filter(receiver__id=request.user.id)
            elif payment_type == 'expense':
                server_obj_list = self.get_queryset().objects.filter(operator__id=request.user.id)
            elif payment_type == 'both':
                server_obj_list = self.get_queryset().objects.filter(Q(receiver__id=request.user.id) |
                                                                     Q(operator__id=request.user.id))
            else:
                return Response(error_result(code=1099, results='参数错误！', total=0))
            if not server_obj_list:
                return Response(error_result(code=1099, results='no', total=0))
            page = self.paginate_queryset(server_obj_list)
            serializer = self.get_serializer(page, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(server_obj_list)))
        except Exception as E:
            print(E)
            return Response(error_result(code=500))


class BaseClassForRechargeLogAndWithdrawLog(CustomNoQuestionsModelViewSet):
    queryset = WithdrawLog
    serializer_class = WithdrawLogModelSerializer
    filter_fields = ('user',)
    pagination_class = SmallPage
    ordering_fields = ('-add_time',)

    class Meta:
        abstract = True

    # 用户提交提现申请, 自动生成订单号，金额必须为100的倍数
    @action(methods=['post'],
            detail=False,
            url_path='create_log',
            )
    def create_log(self, request, *args, **kwargs):
        try:
            # 如果最近的订单为未支付的提现订单，则本次不能通过
            server_obj = self.get_queryset().objects.filter(user__pk=request.user.id).first()
            # print("最近一次", server_obj)
            if server_obj and server_obj.status == 1:
                return Response(error_result(code=1022, results='最近存在未付款的提现订单，本次不能申请'))
            order_unique = request.data['orderUnique']
            order_unique_cache = cache.get(order_unique)
            del request.data['orderUnique']
            if order_unique_cache:
                return Response(error_result(code=1099, results='请不要重复提交提现订单'))
            cache.set(order_unique, True, 1 * 60)
            transaction_type = request.data['transaction_type']
            # 如果是提现，则需要验证余额是否充足，如果是充值，不需要验证
            amount = int(request.data['amount'])
            if amount < 0 or amount % 100 != 0:
                return Response(error_result(code=1099, results='提现金额必须为100的倍数的正整数'))
            if transaction_type == 'withdraw':
                if amount > request.user.bank_point:
                    return Response(error_result(code=1099, results='余额不足！'))
            request.data['status'] = 1
            request.data['remarks'] = '未付款'
            user = request.user
            request.data['user'] = user.id
            request.data['operator'] = user.id
            request.data['order_id'] = "{0}{1}{2}".format(time.strftime('%Y%m%d%H%M%S'),
                                                          str(random.randint(1000, 9999)),
                                                          str(0))
            serializer = self.get_serializer(data=request.data)
            if not serializer.is_valid(raise_exception=False):
                print(serializer.errors)
                return Response(error_result(code=1099, results='提现失败', msg=serializer.errors))
            serializer.save()
            return Response(error_result(code=200, results=serializer.data))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))

    # 管理员审核提现(或充值)申请,分为退款、取消订单和已付款
    @action(methods=['patch'],
            detail=False,
            url_path='update_log_for_admin',
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin])
    def update_log_for_admin(self, request, *args, **kwargs):
        with transaction.atomic():
            sid = transaction.savepoint()
            try:
                status = request.data['status']
                # server_obj是客户订单实例
                obj_id = request.data['id']
                server_obj = self.get_queryset().objects.get(pk=obj_id)
                modify_obj = {}
                # 获取公司账号
                username = Company.objects.first().president
                user_company = User.objects.get(username=username)
                if not((status == 2 and server_obj.status == 1) or
                       (status == 3 and (server_obj.status == 1 or server_obj.status == 2))):
                    Response(error_result(code=1022, msg='状态参数不正确，不能操作', results='no'))
                # 订单付款成功
                if server_obj.status == 1 and status == 2:
                    # 如果是提现订单
                    if isinstance(server_obj, WithdrawLog):
                        # 订单的user和operator是都是申请提现的账户，如果客户此时的余额账户小于想要的提现金额，即余额不足
                        if server_obj.user.bank_point < server_obj.amount:
                            return Response(error_result(code=1099, results='no', msg='余额不足，提现失败'))
                        modify_obj = {'status': status, 'remarks': '批准提现', 'operator': server_obj.user.pk}
                        # 提现成功操作：客户支付库币给公司账号
                        create_customer_bank_point_log_change.delay(operator=server_obj.user.pk,
                                                                    receiver=user_company.pk,
                                                                    point_amount=server_obj.amount,
                                                                    transaction_type=3,
                                                                    remarks='充值')
                    # 如果是充值订单
                    elif isinstance(server_obj, RechargeLog):
                        modify_obj = {'status': status, 'remarks': '批准充值', 'operator': user_company.pk}
                        # 充值成功操作：公司账号支付库币给客户
                        create_customer_bank_point_log_change.delay(operator=user_company.pk,
                                                                    receiver=server_obj.user.pk,
                                                                    point_amount=server_obj.amount,
                                                                    transaction_type=3,
                                                                    remarks='充值')
                    else:
                        return Response(error_result(code=1099, results='no', msg='交易类型错误'))
                # 新建的订单取消，则直接取消，修改状态既可
                elif server_obj.status == 1 and status == 3:
                    modify_obj = {'status': status, 'remarks': '取消订单', 'operator': request.user.id}
                else:
                    return Response(error_result(code=1099, results='no', msg='不支持该交易'))
                serializer = self.get_serializer(instance=server_obj, data=modify_obj, partial=True)
                if not serializer.is_valid(raise_exception=False):
                    print("序列化失败：", serializer.errors)
                    return Response(error_result(code=1099, results='提现失败', msg=serializer.errors))
                serializer.save()
                return Response(error_result(code=200, results="ok"))
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(sid)
                return Response(error_result(code=500))

    # 搜索自己名下的提现记录, 参数为订单状态
    @action(methods=['get'],
            detail=False,
            url_path='get_log_for_owner',
            authentication_classes=[Authentication],
            permission_classes=[IsOwnerPermission]
            )
    def get_log_for_owner(self, request):
        try:
            query_key = request.query_params.get('query_key')
            if query_key and int(query_key) in [0, 1]:
                server_obj_list = self.get_queryset().objects.filter(Q(user__pk=request.user.pk) & Q(status=query_key))
            else:
                server_obj_list = self.get_queryset().objects.filter(user__pk=request.user.pk)
            if len(server_obj_list) == 0:
                return Response(error_result(code=1099, results='no', total=0))
            page = self.paginate_queryset(server_obj_list)
            serializer = self.get_serializer(page, many=True)
            if not serializer:
                return Response(error_result(code=1099, results='no', total=0))
            return Response(error_result(code=200, results=serializer.data, total=len(server_obj_list)))
        except Exception as E:
            print(E)
            return Response(error_result(code=500))

    # 取消自己的订单
    @action(methods=['delete'],
            detail=True,
            url_path='cancel_log_for_owner',
            authentication_classes=[Authentication],
            permission_classes=[IsOwnerPermission]
            )
    def cancel_log_for_owner(self, request, pk):
        try:
            obj_id = int(pk)
            server_obj = self.get_queryset().objects.get(pk=obj_id)
            if not server_obj:
                return Response(error_result(code=1099, results='no', msg='不存在该订单号'))
            if server_obj.status == 3:
                return Response(error_result(code=1099, results='no', msg='该订单已经取消，无需重复'))
            elif server_obj.status == 2:
                return Response(error_result(code=1099, results='no', msg='你没有权限取消订单，请联系管理员取消订单'))
            modify_obj = {'status': 3, 'remarks': '客户自己取消订单'}
            serializer = self.get_serializer(instance=server_obj, data=modify_obj, partial=True)
            if not serializer.is_valid(raise_exception=False):
                print("序列化失败：", serializer.errors)
                return Response(error_result(code=1099, results='反序列化失败', msg=serializer.errors))
            serializer.save()
            return Response(error_result(code=200))
        except Exception as E:
            print(E)
            return Response(error_result(code=500))

    # 搜索所有的提现记录, 参数为最近交易的至今的天数、订单状态、客户的用户名（手机），供管理员使用
    @action(methods=['get'],
            detail=False,
            url_path='get_log_for_admin',
            authentication_classes=[Authentication],
            permission_classes=[IsAdmin]
            )
    def get_log_for_admin(self, request):
        try:
            days = int(request.query_params.get('days'))
            status = int(request.query_params.get('status'))
            real_name = request.query_params.get('real_name')
            if status not in [0, 1, 2, 3, 4]:
                return Response(error_result(code=1099, results='参数status错误', total=0))
            if days < 0:
                return Response(error_result(code=1099, results='参数days错误', total=0))
            current_date = date.today()
            past_date = current_date - timedelta(days=days)
            server_obj_list = []
            if not real_name and days == 0 and status == 0:
                server_obj_list = self.get_queryset().objects.all()
            elif not real_name and days == 0:
                server_obj_list = self.get_queryset().objects.filter(status=status)
            elif not real_name and days > 0 and status == 0:
                server_obj_list = self.get_queryset().objects.filter(add_time__gt=past_date)
            elif not real_name and days > 0 and status > 0:
                server_obj_list = self.get_queryset().objects.filter(Q(add_time__gt=past_date) | Q(status=status))
            elif real_name and days == 0 and status == 0:
                server_obj_list = self.get_queryset().objects.filter(Q(user__real_name__contains=real_name) |
                                                                     Q(user__phone__contains=real_name))
            elif real_name and days == 0 and status > 0:
                server_obj_list = self.get_queryset().objects.filter((Q(user__real_name__contains=real_name) |
                                                                      Q(user__phone__contains=real_name)) &
                                                                     Q(status=status))
            elif real_name and days > 0 and status == 0:
                server_obj_list = self.get_queryset().objects.filter((Q(user__real_name__contains=real_name) |
                                                                      Q(user__phone__contains=real_name)) &
                                                                     Q(add_time__gt=past_date))
            elif real_name and days > 0 and status > 0:
                server_obj_list = self.get_queryset().objects.filter((Q(user__real_name__contains=real_name) |
                                                                      Q(user__phone__contains=real_name)) &
                                                                     Q(add_time__gt=past_date) &
                                                                     Q(status=status))
            if len(server_obj_list) == 0:
                return Response(error_result(code=1099, results='no', total=0))
            page = self.paginate_queryset(server_obj_list)
            serializer = self.get_serializer(page, many=True)
            if not serializer:
                return Response(error_result(code=1099, results='no', total=0))
            return Response(error_result(code=200, results=serializer.data, total=len(server_obj_list)))
        except Exception as E:
            print(E)
            return Response(error_result(code=500))


class RechargeLogModelViewSet(BaseClassForRechargeLogAndWithdrawLog):
    queryset = RechargeLog
    serializer_class = RechargeLogModelSerializer
    filter_fields = ('user',)
    pagination_class = SmallPage
    ordering_fields = ('-add_time',)


# 注意：以下类继承自BaseClassForRechargeLogAndWithdrawLog，所以不用实现具体的方法
class WithdrawLogModelViewSet(BaseClassForRechargeLogAndWithdrawLog):
    queryset = WithdrawLog
    serializer_class = WithdrawLogModelSerializer
    filter_fields = ('user',)
    pagination_class = SmallPage
    ordering_fields = ('-add_time',)


# 注意：同上
class SponsorModelViewSet(CustomNoQuestionsModelViewSet):
    queryset = Sponsor
    serializer_class = SponsorModelSerializer
    filter_fields = ('user',)
    pagination_class = SmallPage
    ordering_fields = ('-add_time',)

    # 查看所有赞助记录
    @action(methods=['get'],
            detail=False,
            url_path='get_sponsor_record')
    def get_sponsor_record(self, request):
        try:
            objs = self.get_queryset().objects.all()
            if not objs:
                return Response(error_result(code=1099, results={}, msg='没有记录'))
            serializer = self.get_serializer(objs, many=True)
            print("赞助记录：", objs)
            return Response(error_result(code=200, results=serializer.data, total=len(objs)))
        except Exception as e:
            print(e)
            return Response(error_result(code=500))


class DailySignatureAPIView(APIView):

    def post(self, request):
        try:
            user = self.request.user
            phone = user.phone
            cache_key = 'daily_signature' + phone
            last_signature_time = cache.get(cache_key)
            # 用于标记本次签到是否成功
            flag = False
            point_amount = 0
            # 获取当前日期
            today = datetime.datetime.now().date()
            # 获取昨天的日期
            yesterday = today - datetime.timedelta(days=1)
            if not last_signature_time:
                flag = True
                point_amount = 2
            elif yesterday == last_signature_time.date():
                flag = True
                point_amount = 3
            elif yesterday > last_signature_time.date():
                flag = True
                point_amount = 2
            if flag:
                # 本次签到成功，则重新设置签到时间,过期时长为当前时间到第二天凌晨零点的小时
                expiration_hour = 24 - datetime.datetime.now().hour
                cache.set(cache_key, datetime.datetime.now(), expiration_hour*3600)
                # 创建交易记录,公司账号打钱给敲到者
                username = Company.objects.first().president
                user_company = User.objects.get(username=username)
                create_customer_bank_point_log_change.delay(operator=user_company.pk,
                                                            receiver=request.user.pk,
                                                            point_amount=point_amount,
                                                            transaction_type=12,
                                                            remarks='每日签到')
                user_new = User.objects.get(pk=user.pk)
                serializer = UserSimpleModelSerializer(user_new)
                return Response(error_result(code=200, results=serializer.data))
            else:
                user_new = User.objects.get(pk=user.pk)
                serializer = UserSimpleModelSerializer(user_new)
                return Response(error_result(code=200, results=serializer.data, msg='今日已签，记得明天再来哦^_^'))
        except Exception as E:
            print(E)
            return Response(error_result(code=500))


class ClassGradeViewSet(CustomNoQuestionsModelViewSet):

    queryset = ClassGrade
    serializer_class = ClassGradeModelSerializer

    # 查询所有未毕业班级和已毕业的班级，并以入学年份分类
    @action(methods=['get'],
            detail=False,
            authentication_classes=[Authentication],
            )
    def get_all_class_sorted_graduated(self, request):
        try:
            class_list = self.get_queryset().objects.all().values('id', 'name', 'graduated')
            # 先按 graduated 分类
            class_new_list = {"ungraduated": [], "graduated": []}
            # 年份在数组里的索引号, 第一个为ungraduated；第二个为graduated
            year_index_map = [{}, {}]
            map_index_dict = {False: 0, True: 1}
            graduate_dict = {True: "graduated", False: 'ungraduated'}
            for item in class_list:
                # 如果该年份未出现过，则新建该年级，并添加一个班级
                # 否则在年份索引映射表中找到
                map_index = map_index_dict[item['graduated']]
                if item['name'][:5] not in year_index_map[map_index]:
                    year_index_map[map_index][item['name'][:5]] = len(class_new_list[graduate_dict[item['graduated']]])
                    class_new_list[graduate_dict[item['graduated']]].append({'name': item['name'][:5], 'class_list': [item]})
                else:
                    index = year_index_map[map_index][item['name'][:5]]
                    class_new_list[graduate_dict[item['graduated']]][index]['class_list'].append(item)
            return Response(error_result(code=200, results=class_new_list))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 设置为毕业班或非毕业班（批量），参数只接收数组类型和操作类型
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            )
    def set_graduated(self, request, *args, **kwargs):
        try:
            class_list = request.data['class_list']
            operate = request.data['operate']
            operate_map = {'graduated': True, 'ungraduated': False}
            if isinstance(class_list, list):
                if len(class_list) == 0:
                    return Response(error_result(code=1099, results='空数组', msg='空数组'))
            else:
                print(f"{class_list} 不是一个数组！")
                return Response(error_result(code=1099, results='必须提交数组', msg='必须提交数组'))
            # 由于前段比较方便获取name字段，因此把id改为name字段了
            class_grade_list_server = ClassGrade.objects.filter(name__in=class_list).update(graduated=operate_map[operate])
            # result = ClassGradeModelSerializer(class_grade_list_server).data
            return Response(error_result(code=200, msg="恭喜，添加班级成功！", results='ok'))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 新增班级
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            )
    def create_class(self, request, *args, **kwargs):
        try:
            class_name = request.data['name']
            pattern = r'^\d{4}级\d{1,2}班$'
            if not re.match(pattern, class_name):
                return Response(error_result(code=1008, msg='班级名称不合理', results="no"))
            obj = self.get_queryset().objects.filter(name=class_name)
            if len(obj) > 0:
                return Response(error_result(code=1009, msg='班级已存在', results="no"))
            request.data['graduated'] = False
            serializer = self.get_serializer(data=request.data)
            if not serializer.is_valid():
                print("序列化错误:", serializer.errors)
                return Response(error_result(code=406, msg=serializer.errors, results=data_error_text))
            serializer.save()
            return Response(error_result(code=200, msg="恭喜，添加班级成功！", results='OK'))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 筛选某个班级下的老师或者学生，参数is_teacher来决定角色
    @action(methods=['get'],
            detail=False,
            authentication_classes=[Authentication],
            )
    def get_user_by_class(self, request):
        try:
            is_teacher = request.query_params.get('is_teacher')
            if isinstance(is_teacher, str):
                if is_teacher == 'true':
                    is_teacher = True
                elif is_teacher == 'false':
                    is_teacher = False
                else:
                    return Response(error_result(code=1099, msg='is_teacher 的值不合理', results=data_error_text))
            class_id = request.query_params.get('class_id')
            class_server_list = UserOfClass.objects.filter(Q(class_grade__id=class_id) & Q(user__is_teacher=is_teacher))
            serializer = UserOfClassModelSerializer(class_server_list, many=True)
            return Response(error_result(code=200, results=serializer.data))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 筛选某个教师任教的班级（未毕业)
    @action(methods=['get'],
            detail=False,
            authentication_classes=[Authentication],
            )
    def get_class_by_teacher(self, request):
        try:
            user_id = request.user.id
            class_user_server_list = UserOfClass.objects.filter(
                Q(user__id=user_id) & Q(class_grade__graduated=False))
            class_id_list = convert_dic_list(dict_list=class_user_server_list.values('class_grade'), key='class_grade')
            class_obj_list = ClassGrade.objects.filter(id__in=class_id_list)
            serializer = ClassGradeSimpleModelSerializer(class_obj_list, many=True)
            return Response(error_result(code=200, results=serializer.data, total=len(class_obj_list)))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))

    # 关联一个班级和多个用户(已注册过)
    @action(methods=['post'],
            detail=False,
            authentication_classes=[Authentication],
            )
    def add_link(self, request, *args, **kwargs):
        try:
            class_id = request.data['class_id']
            user_list = request.data['user_list']
            if isinstance(user_list, list):
                if len(user_list) == 0:
                    return Response(error_result(code=1099, results='空数组', msg='空数组'))
            else:
                return Response(error_result(code=1098, results='no', msg='用户必须是数组格式'))
            user_server_list = User.objects.filter(username__in=user_list)
            class_obj_server = ClassGrade.objects.get(id=class_id)
            class_obj_server.user.add(*user_server_list)
            class_obj_server.save()
            return Response(error_result(code=200, msg="恭喜，添加班级成功！", results='OK'))
        except Exception as e:
            print('Exception:', e)
            return Response(error_result(code=500))
